#pragma once
#include <iostream>
#include <sys/socket.h>
#include <sys/types.h>
#include <cstring>
#include <string>
#define SEP " "
#define SEP_LEN strlen(SEP) //不能使用sizeof();
#define LINE_SEP "\r\n"
#define LINE_SEP_LEN strlen(LINE_SEP)

std::string enLength(const std::string &text)
{
    std::string send_string = std::to_string(text.size());
    send_string += LINE_SEP;
    send_string += text;
    send_string += LINE_SEP;

    return send_string;
}

//content_len"\r\n"x op y"\r\n 一个完整的报文
bool deLength(const std::string &package, std::string *text)
{
    ssize_t pos = package.find(LINE_SEP);
    if (pos == std::string::npos) return false;

    std::string text_len_string = package.substr(0, pos);
    int text_len = std::stoi(text_len_string);
    *text = package.substr(pos + LINE_SEP_LEN, text_len);
    return true;
}

// 假设接收到的是 "content_len"\r\n"x op y"\r\n"content_len"\r\n"x op y"\r\n
bool recvPackage(const int sock, std::string &inbuffer, std::string *text)
{
    char buffer[1024];//充当接收缓冲区
    while (true)
    {
        ssize_t n = recv(sock, buffer, sizeof(buffer)-1, 0);
        if (n > 0)
        {
            buffer[n] = 0;
            //buffer里面的内容每次都会被覆盖，所以每次都需要将buffer里的内容放到inbuffer中
            inbuffer += buffer;

            size_t pos = inbuffer.find(LINE_SEP);
            //没有找到 LINE_SEP 说明连一个报文的头部都没读取到，那么就继续读
            if (pos == std::string::npos) continue;
            //截取一个报文的头部
            std::string text_len_string = inbuffer.substr(0, pos);
            int text_len = std::stoi(text_len_string);
            //计算一个完整报文的长度，也就是 "content_len"\r\n"x op y"\r\n 的长度
            int total_len = text_len_string.size() + 2 * LINE_SEP_LEN + text_len;

            if (inbuffer.size() < total_len)
            {
                //到这里，说明连一个完整的报文都没有
                std::cout << "你输入的消息，没有严格遵守我们的协议，正在等待后续的内容, continue" << std::endl;
                continue;
            }

            //至少有一个完整的报文
            *text = inbuffer.substr(0, total_len);
            inbuffer.erase(0, total_len);
            break;
        }
        else return false;
    }
    return true;
}


class Request
{
public:
    Request() : _x(0), _y(0), _op(0)
    {}

    Request(int x, int y, char op) : _x(x), _y(y), _op(op)
    {}

    //序列化
    bool serialize(std::string *out)
    {
        *out = "";
        std::string x_str = std::to_string(_x);
        std::string y_str = std::to_string(_y);

        *out += x_str;
        *out += SEP;
        *out += _op;
        *out += SEP;
        *out += y_str;

        return true;
    }

    //反序列化
    //将 "x op y" 变成结构化
    bool deserialize(const std::string &in)
    {
        ssize_t left = in.find(SEP);
        ssize_t right = in.rfind(SEP);
        if (left == std::string::npos || right == std::string::npos) return false;
        if (left == right) return false;
        //确保两个空格之间只有一个操作符
        if (right - (left + SEP_LEN) != 1) return false;

        std::string x_str = in.substr(0, left);
        std::string y_str = in.substr(right + SEP_LEN);

        _x = std::stoi(x_str);
        _y = std::stoi(y_str);
        _op = in[left + SEP_LEN];

        return true;
    }
public:
    int _x;
    int _y;
    char _op;
};

class Response
{
public:
    Response() : _exitcode(0), _result(0) {}

    Response(int exitcode, int result) : _exitcode(exitcode), _result(result) {}

    //对结果进行序列化
    bool serialize(std::string *out)
    {
        *out = "";
        std::string exitcode = std::to_string(_exitcode);
        std::string ret_string = std::to_string(_result);

        *out += exitcode;
        *out += SEP;
        *out += ret_string;

        return true;
    }

    bool deserialize(const std::string &in)
    {
        int pos = in.find(SEP);
        if (pos == std::string::npos) return false;

        std::string exitcode = in.substr(0, pos);
        std::string ret_string = in.substr(pos + SEP_LEN);

        _exitcode = std::stoi(exitcode);
        _result = std::stoi(ret_string);

        return true;
    }
public:
    int _exitcode; // 0表示成功，非0表示失败
    int _result; // 计算结果
};